#include "pch.h"
#include "AppConfig.h"
#include "..\Common\Utility.h"

CAppConfig::CAppConfig()
{
	AssertInUIThread();
}

CAppConfig::~CAppConfig()
{
	AssertInUIThread();
}

bool CAppConfig::Init()
{
	AssertInUIThread();

	std::wstring strFileName;
	bool bRet = Util::GetConfigFile(strFileName) &&
		LoadClientRoot(strFileName.c_str()) &&
		LoadPluginCfgs(strFileName.c_str()) &&
		LoadSubDirCfgs(strFileName.c_str());

	if (!bRet)
		LogError(L"Load config error: %s", strFileName);

	return bRet;
}

void CAppConfig::Exit()
{
	AssertInUIThread();
}

bool CAppConfig::LoadClientRoot(LPCWSTR lpFileName)
{
	/*
	[Main]
	ClientRoot=D:\Test\Client\
	*/
	wchar_t szBuffer[MAX_PATH];
	if (GetPrivateProfileStringW(L"Main", L"ClientRoot", NULL, szBuffer, ARRAYSIZE(szBuffer), lpFileName) < 4)
		return false;

	std::wstring& strPath = m_strClientRoot = szBuffer;
	Util::FormatFilePath(strPath);

	if (strPath[0] >= 'a' && strPath[0] <= 'z')
		strPath[0] += 'A' - 'a';

	if (!(strPath[0] >= 'A' && strPath[0] <= 'Z' && strPath[1] == ':' && strPath[2] == '\\' && strPath.find(L"\\\\") == std::wstring::npos))
	{
		LogError(L"ClientRoot error: %s", szBuffer);
		return false;
	}

	DWORD dwError = 0;
	if (CreateDirectoryW(strPath.c_str(), NULL) || (dwError = GetLastError()) == ERROR_ALREADY_EXISTS)
		return true;

	LogError(L"CreateDirectory error: %s, Error=%d", strPath, dwError);
	return false;
}

bool CAppConfig::LoadPluginCfgs(LPCWSTR lpFileName)
{
	/*
	[Plugins]
	File=FilePlugin.dll
	*/
	wchar_t szBuffer[1024];
	if (GetPrivateProfileSectionW(L"Plugins", szBuffer, ARRAYSIZE(szBuffer), lpFileName) < 3)
		return false;

	for (LPWSTR lpBuffer = szBuffer; *lpBuffer; )
	{
		LPWSTR lpPluginName = lpBuffer;
		lpBuffer += wcslen(lpBuffer) + 1;

		if (LPWSTR lpPluginDll = wcschr(lpPluginName, '='))
		{
			*lpPluginDll++ = 0;

			if (*lpPluginName && *lpPluginDll)
				m_vecPluginCfgs.emplace_back(PluginCfg{ lpPluginName, lpPluginDll });
		}
	}

	return m_vecPluginCfgs.size() != 0;
}

bool CAppConfig::LoadSubDirCfgs(LPCWSTR lpFileName)
{
	/*
	[SubDirs]
	Tools=File|D:\Test\Server\Tools
	*/
	wchar_t szBuffer[4096];
	if (GetPrivateProfileSectionW(L"SubDirs", szBuffer, ARRAYSIZE(szBuffer), lpFileName) < 5)
		return false;

	for (LPWSTR lpBuffer = szBuffer; *lpBuffer; )
	{
		LPWSTR lpSubPath = lpBuffer;
		lpBuffer += wcslen(lpBuffer) + 1;

		if (*lpSubPath == '\\' || *lpSubPath == '/')
			lpSubPath++;

		if (LPWSTR lpPluginName = wcschr(lpSubPath, '='))
		{
			*lpPluginName++ = 0;

			if (LPWSTR lpServerInfo = wcschr(lpPluginName, '|'))
			{
				*lpServerInfo++ = 0;

				if (*lpSubPath && *lpPluginName && *lpServerInfo)
					InsertSubDirCfg(SubDirCfg{ lpSubPath, lpPluginName, lpServerInfo });
			}
		}
	}

	// SubDirs cannot contain each other
	for (size_t i = 1; i < m_vecSubDirCfgs.size(); i++)
	{
		const auto& str0 = m_vecSubDirCfgs[i - 1].strSubPath;
		const auto& str1 = m_vecSubDirCfgs[i].strSubPath;

		if (str0.size() <= str1.size() && _wcsnicmp(str0.c_str(), str1.c_str(), str0.size()) == 0)
			return false;
	}

	return m_vecSubDirCfgs.size() != 0;
}

void CAppConfig::InsertSubDirCfg(SubDirCfg&& subDirCfg)
{
	Util::FormatFilePath(subDirCfg.strSubPath);

	// Ordered insertion instead of std::sort
	auto it = m_vecSubDirCfgs.begin();
	for (; it != m_vecSubDirCfgs.end() && _wcsicmp(it->strSubPath.c_str(), subDirCfg.strSubPath.c_str()) < 0; ++it);
	m_vecSubDirCfgs.insert(it, std::move(subDirCfg));
}
